// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 
// Source File Name:   IsoMessage.java

package com.solab.iso8583;

import com.solab.iso8583.common.ByteUtil;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.*;

// Referenced classes of package com.solab.iso8583:
//			IsoValue, IsoType

public class IsoMessage
{

	static final byte HEX[] = {
		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 
		65, 66, 67, 68, 69, 70
	};
	private int type;
	private boolean binary;
	private Hashtable fields;
	private String isoHeader;
	private int etx;

	public IsoMessage()
	{
		fields = new Hashtable();
		etx = -1;
	}

	public IsoMessage(String header)
	{
		fields = new Hashtable();
		etx = -1;
		isoHeader = header;
	}

	public String getIsoHeader()
	{
		return isoHeader;
	}

	public void setType(int value)
	{
		type = value;
	}

	public int getType()
	{
		return type;
	}

	public void setBinary(boolean flag)
	{
		binary = flag;
	}

	public boolean isBinary()
	{
		return binary;
	}

	public void setEtx(int value)
	{
		etx = value;
	}

	public Object getObjectValue(int field)
	{
		IsoValue v = (IsoValue)fields.get(new Integer(field));
		if (v == null)
			return null;
		else
			return v.getValue();
	}

	public IsoValue getField(int field)
	{
		return (IsoValue)fields.get(new Integer(field));
	}

	public void setField(int index, IsoValue field)
	{
		if (index < 2 || index > 128)
			throw new IndexOutOfBoundsException("Field index must be between 2 and 128");
		if (field == null)
			fields.remove(new Integer(index));
		else
			fields.put(new Integer(index), field);
	}

	public void setValue(int index, Object value, IsoType t, int length)
	{
		if (index < 2 || index > 128)
			throw new IndexOutOfBoundsException("Field index must be between 2 and 128");
		if (value == null)
		{
			fields.remove(new Integer(index));
		} else
		{
			IsoValue v = null;
			if (length != 0 || t.needsLength())
				v = new IsoValue(t, value, length);
			else
				v = new IsoValue(t, value);
			fields.put(new Integer(index), v);
		}
	}

	public boolean hasField(int idx)
	{
		return fields.get(new Integer(idx)) != null;
	}

	public void write(OutputStream outs, int lengthBytes)
		throws IOException
	{
		if (lengthBytes > 4)
			throw new IllegalArgumentException("The length header can have at most 4 bytes");
		byte data[] = writeInternal();
		if (lengthBytes > 0)
		{
			int l = data.length;
			if (etx > -1)
				l++;
			byte buf[] = new byte[lengthBytes];
			int pos = 0;
			if (lengthBytes == 4)
			{
				buf[0] = (byte)((l & 0xff000000) >> 24);
				pos++;
			}
			if (lengthBytes > 2)
			{
				buf[pos] = (byte)((l & 0xff0000) >> 16);
				pos++;
			}
			if (lengthBytes > 1)
			{
				buf[pos] = (byte)((l & 0xff00) >> 8);
				pos++;
			}
			buf[pos] = (byte)(l & 0xff);
			outs.write(buf);
		}
		outs.write(data);
		if (etx > -1)
			outs.write(etx);
		outs.flush();
	}

	public ByteBuffer writeToBuffer(int lengthBytes)
	{
		if (lengthBytes > 4)
			throw new IllegalArgumentException("The length header can have at most 4 bytes");
		byte data[] = writeInternal();
		ByteBuffer buf = ByteBuffer.allocate(lengthBytes + data.length + (etx <= -1 ? 0 : 1));
		if (lengthBytes > 0)
		{
			int l = data.length;
			if (etx > -1)
				l++;
			byte bbuf[] = new byte[lengthBytes];
			int pos = 0;
			if (lengthBytes == 4)
			{
				bbuf[0] = (byte)((l & 0xff000000) >> 24);
				pos++;
			}
			if (lengthBytes > 2)
			{
				bbuf[pos] = (byte)((l & 0xff0000) >> 16);
				pos++;
			}
			if (lengthBytes > 1)
			{
				bbuf[pos] = (byte)((l & 0xff00) >> 8);
				pos++;
			}
			bbuf[pos] = (byte)(l & 0xff);
			buf.put(bbuf);
		}
		buf.put(data);
		if (etx > -1)
			buf.put((byte)etx);
		buf.flip();
		return buf;
	}

	protected byte[] writeInternal()
	{
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		if (isoHeader != null)
			try
			{
				bout.write(ByteUtil.Int2ByteArray(Integer.valueOf(isoHeader, 2).intValue(), 10));
			}
			catch (IOException ioexception) { }
		if (binary)
		{
			bout.write((type & 0xff00) >> 8);
			bout.write(type & 0xff);
		} else
		{
			String x = Integer.toHexString(type);
			if (x.length() < 4)
				bout.write(48);
			try
			{
				bout.write(x.getBytes());
			}
			catch (IOException ioexception1) { }
		}
		ArrayList keys = new ArrayList();
		keys.addAll((Collection)fields.keySet());
		Collections.sort(keys);
		BitSet bs = new BitSet(64);
		for (Iterator iter = keys.iterator(); iter.hasNext(); bs.set(((Integer)iter.next()).intValue() - 1));
		if (bs.length() > 64)
		{
			BitSet b2 = new BitSet(128);
			b2.or(bs);
			bs = b2;
			bs.set(0);
		}
		if (binary)
		{
			int pos = 128;
			int b = 0;
			for (int i = 0; i < bs.size(); i++)
			{
				if (bs.get(i))
					b |= pos;
				pos >>= 1;
				if (pos == 0)
				{
					bout.write(b);
					pos = 128;
					b = 0;
				}
			}

		} else
		{
			int pos = 0;
			int lim = bs.size() / 16;
			for (int i = 0; i < lim; i++)
			{
				int nibble = 0;
				if (bs.get(pos++))
					nibble += 32768;
				if (bs.get(pos++))
					nibble += 16384;
				if (bs.get(pos++))
					nibble += 8192;
				if (bs.get(pos++))
					nibble += 4096;
				if (bs.get(pos++))
					nibble += 2048;
				if (bs.get(pos++))
					nibble += 1024;
				if (bs.get(pos++))
					nibble += 512;
				if (bs.get(pos++))
					nibble += 256;
				if (bs.get(pos++))
					nibble += 128;
				if (bs.get(pos++))
					nibble += 64;
				if (bs.get(pos++))
					nibble += 32;
				if (bs.get(pos++))
					nibble += 16;
				if (bs.get(pos++))
					nibble += 8;
				if (bs.get(pos++))
					nibble += 4;
				if (bs.get(pos++))
					nibble += 2;
				if (bs.get(pos++))
					nibble++;
				try
				{
					bout.write(ByteUtil.Int2ByteArray(nibble, 2));
				}
				catch (IOException e)
				{
					System.out.println("###################???BitMap ???################## IsoMessage ?? writeInternal ????");
					e.printStackTrace();
				}
			}

		}
		for (Iterator iter = keys.iterator(); iter.hasNext();)
		{
			IsoValue v = (IsoValue)fields.get(iter.next());
			try
			{
				v.write(bout, binary);
			}
			catch (IOException ioexception2) { }
		}

		byte total[] = bout.toByteArray();
		byte length[] = ByteUtil.Int2ByteArray(total.length, 2);
		return ByteUtil.byteAndByte(length, total);
	}

}
